﻿using DuplicateDetectionRuleRepublisher.Helpers;
using Microsoft.Crm.Sdk.Messages;
using Microsoft.Xrm.Client;
using Microsoft.Xrm.Client.Services;
using Microsoft.Xrm.Client.Windows.Controls.ConnectionDialog;
using Microsoft.Xrm.Sdk;
using System;
using System.Collections.Generic;
using System.Configuration;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows;

namespace DuplicateDetectionRuleRepublisher
{
    class Program
    {
        private const string CONN_STRING_ENCRYPTED = "ConnectionStringEncrypted";
        private const string CONN_STRING = "ConnectionString";

        private static string connString = "";
        private static Options options = new Options();

        [STAThread]
        static void Main(string[] args)
        {
            try
            {
                Run(args);
            }
            catch (Exception e)
            {
                PrintError(e);
                throw;
            }
        }

        private static void Run(string[] args)
        {
            ReadCommandLine(args);

            Configuration config = ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None);
            ReadConnString(config);
            PromptToUseConnString();
            PromptForNewConnString(config);
            if (string.IsNullOrWhiteSpace(connString))
                return;  //  The End

            //Console.WriteLine("Connection String: \n" + connString);

            using (var crm = new OrganizationService(CrmConnection.Parse(connString)))
            {
                ShowDuplicateDetectionSettings(crm);
                ShowRuleStatus(crm);
                PublishRules(crm);
            }
            Console.WriteLine("Done!");
        }
        private static void PublishRules(IOrganizationService crm)
        {
            using (var ctx = new XrmServiceContext(crm))
            {
                var inactiveRules = ctx.DuplicateRuleSet.Where(r => r.StateCode == DuplicateRuleState.Inactive);
                foreach (var rule in inactiveRules)
                {
                    Console.WriteLine("Publishing [{0}]...", rule.Name);
                    var response = (PublishDuplicateRuleResponse)crm.Execute(new PublishDuplicateRuleRequest { DuplicateRuleId = rule.Id });
                }
            }
        }
        private static void ShowRuleStatus(IOrganizationService crm)
        {
            using (var ctx = new XrmServiceContext(crm))
            {
                var rules = from d in ctx.DuplicateRuleSet select d;
                foreach (var rule in rules)
                {
                    Console.WriteLine("{0} is {1}", rule.Name, rule.StateCode);
                }
            }
        }
        private static void ShowDuplicateDetectionSettings(IOrganizationService crm)
        {
            using (var ctx = new XrmServiceContext(crm))
            {
                var org = (from o in ctx.OrganizationSet select o).FirstOrDefault();
                Console.WriteLine("Organization: " + org.Name);
                Console.WriteLine("IsDuplicateDetectionEnabled: " + org.IsDuplicateDetectionEnabled);
            }
        }
        private static void ReadCommandLine(string[] args)
        {
            if (!CommandLine.Parser.Default.ParseArguments(args, options))
            {
                var results = CommandLine.Text.HelpText.AutoBuild(options);
                Console.Write(results);
                Console.ReadLine();
            }
            Console.WriteLine("Autorun: " + options.Autorun);
        }
        private static void PromptForNewConnString(Configuration config)
        {
            if (string.IsNullOrWhiteSpace(connString))
            {
                connString = ConnectionWizard();
                if (!string.IsNullOrWhiteSpace(connString))
                {
                    using (var aes = new Helpers.SimpleAES())
                    {
                        var encryptedConnString = aes.Encrypt(connString);
                        config.AppSettings.Settings[CONN_STRING_ENCRYPTED].Value = encryptedConnString;
                        config.Save(ConfigurationSaveMode.Modified, true);
                        ConfigurationManager.RefreshSection("appSettings");
                        MessageBox.Show("Connection Information saved to DuplicateDetectionRuleRepublish.exe.config. \n\n if you run with the command line arg --Autorun you will not be prompted again.", "Autorun Next Time", MessageBoxButton.OK);
                    }
                }
            }
        }
        private static void PromptToUseConnString()
        {
            if (!options.Autorun && !string.IsNullOrWhiteSpace(connString))
            {
                var results = MessageBox.Show("Use Connection String in DuplicateDetectionRuleRepublisher.exe.config file?", "Use existing", MessageBoxButton.YesNoCancel);
                if (results != MessageBoxResult.Yes)
                    connString = "";
            }
        }
        private static void ReadConnString(Configuration config)
        {
            connString = config.AppSettings.Settings[CONN_STRING].Value.ToString();
            if (string.IsNullOrWhiteSpace(connString))
            {
                var encryptedConnString = config.AppSettings.Settings[CONN_STRING_ENCRYPTED].Value.ToString();
                if (!string.IsNullOrWhiteSpace(encryptedConnString))
                {
                    using (var aes = new Helpers.SimpleAES())
                    {
                        connString = aes.Decrypt(encryptedConnString);
                    }
                }
            }
        }
        private static string ConnectionWizard()
        {
            ConnectionDialog dlgConnect = new ConnectionDialog();
            var connected = dlgConnect.ShowDialog();

            if (connected.Value == true)
            {
                return dlgConnect.ConnectionString;
            }
            return null;
        }
        private static void PrintError(Exception e)
        {
            Console.WriteLine(e.ToString());
            Console.WriteLine(e.Message);
            Console.WriteLine(e.StackTrace);
            if (e.InnerException != null)
                PrintError(e.InnerException);
        }
    }
}
